package com.lmbsvn.core.shiro.credential;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 继承 Shiro HashedCredentialsMatcher
 * 重写 doCredentialsMatch 方法,目的：增加错误尝试次数
 * @author lumingbao
 */
public class LimitRetryHashedMatcher extends HashedCredentialsMatcher {
	
	private static int ExcessiveAttemptsNumber = 10;//允许错误次数
	
	private Cache<String, AtomicInteger> passwordRetryCache;
	
	public LimitRetryHashedMatcher(CacheManager cacheManager) {
        passwordRetryCache = cacheManager.getCache("passwordRetryCache");
    }
	
	@Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        String username = (String)token.getPrincipal();
        //retry count + 1
        AtomicInteger retryCount = passwordRetryCache.get(username);
        if(retryCount == null) {
            retryCount = new AtomicInteger(0);
            passwordRetryCache.put(username, retryCount);
        }
        if(retryCount.incrementAndGet() > ExcessiveAttemptsNumber) {
            //if retry count > 5 throw
            throw new ExcessiveAttemptsException("username: " + username + " tried to login more than " + ExcessiveAttemptsNumber + " times in period");
        }
        boolean matches = super.doCredentialsMatch(token, info);
        if(matches) {
            //clear retry count
            passwordRetryCache.remove(username);
        }
        return matches;
    }
}
